package org.wangp.framework.core.config

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.scheduling.annotation.AsyncConfigurerSupport
import org.springframework.scheduling.annotation.EnableAsync
import java.util.concurrent.*
import kotlin.concurrent.thread
import kotlin.math.max

/**
 * @author wangpeng (๑•ᴗ•๑)
 * @since 2021/10/13 22:14
 */
@Configuration
@EnableAsync(proxyTargetClass = true, order = Int.MAX_VALUE)
class AsyncConfiguration : AsyncConfigurerSupport() {

	companion object {
		val log: Logger = LoggerFactory.getLogger(AsyncConfiguration::class.java)
		private const val THREAD_PREFIX = "async-exec-"
	}

	@Bean("asyncThreadPool")
	override fun getAsyncExecutor(): Executor = ThreadPoolExecutor(
		max(Runtime.getRuntime().availableProcessors() / 4, 1),
		max(Runtime.getRuntime().availableProcessors() / 2, 1),
		30,
		TimeUnit.MINUTES,
		ArrayBlockingQueue(1000, true),
		ThreadFactory {
			val thread = thread(
				start = false
			) { it.run() }
			thread.name = "${THREAD_PREFIX}${thread.id}"
			thread
		})

	override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler =
		AsyncUncaughtExceptionHandler { throwable, method, arrayOfAnys ->
			log.error("exec async method error [${method.name}] ${arrayOfAnys.contentToString()}", throwable)
		}
}
